package com.example.ktdemo.draghelper.widget

import android.animation.ValueAnimator
import android.content.Context
import android.util.AttributeSet
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
import android.widget.LinearLayout
import android.widget.RelativeLayout
import androidx.core.animation.doOnEnd
import androidx.customview.widget.ViewDragHelper
import com.example.ktdemo.R
import com.north.light.libmusicplayerx.utils.KtLogUtil.d
import java.util.concurrent.atomic.AtomicBoolean

/**
 * 实现拖拽出界外的布局
 */
class DragLayout @JvmOverloads constructor(
    context: Context?,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : LinearLayout(context, attrs, defStyleAttr) {
    private lateinit var topView: ViewGroup
    private lateinit var dragBtn: ViewGroup
    private lateinit var bottomView: ViewGroup
    private var dragRecyclerView: DragRecyclerView? = null

    //拖拽控件高度
    private var dragBtnHeight = 0

    //顶部控件的高度
    private var mTopHeight = 0

    //停止位置的高度
    private var stopHeight = 0
    private lateinit var dragHelper: ViewDragHelper
    private var MIN_TOP = 0 // 距离顶部最小的距离
    private var MIN_BOTTOM = 0 // 距离底部最小的距离


    //drag recyclerview是否已经到达顶部--如果有
    private var isDragRecyInTop: AtomicBoolean = AtomicBoolean(true)

    //触摸后，是否有ViewDragHelper滑动具体
    private var mDragAfterTouch = false

    //动画时间
    private val mSetOffAnimTime = 200L

    private fun dp2px(dpValue: Int): Int {
        return context.resources.displayMetrics.density.toInt() * dpValue
    }

    private var mListener: DragLayoutEventListener? = null

    init {
        init()
    }

    private fun init() {
        //插入一个布局
        val inflateView: LinearLayout = LayoutInflater.from(context).inflate(
            R.layout.item_drag_helper_view,
            this, false
        ) as LinearLayout
        addView(inflateView)
        val inflateParams = inflateView.layoutParams
        inflateParams.width = ViewGroup.LayoutParams.MATCH_PARENT
        inflateParams.height = ViewGroup.LayoutParams.MATCH_PARENT
        inflateView.layoutParams = inflateParams
        //开始设置
        dragHelper = ViewDragHelper.create(inflateView, 1.0f, object : ViewDragHelper.Callback() {
            override fun onViewDragStateChanged(state: Int) {
                super.onViewDragStateChanged(state)
                d("ViewDragHelper onViewDragStateChanged: $state")
                if (state == 0) {
                    //判断当前位置，吸附到上中下三个位置
                    resetPositionAnim()
                }
            }

            override fun tryCaptureView(child: View, pointerId: Int): Boolean {
                //只处理dragBtn
                val isTopLayout = (child === topView)
                val isDragLayout = (child === dragBtn)
                val isBottomLayout = (child === bottomView)
                d("ViewDragHelper tryCaptureView isTopLayout: $isTopLayout")
                d("ViewDragHelper tryCaptureView isDragLayout: $isDragLayout")
                d("ViewDragHelper tryCaptureView isBottomLayout: $isBottomLayout")
                mDragAfterTouch = false
                if (isDragLayout) {
                    return true
                } else if (isBottomLayout) {
                    d("滚动到顶部2222: mTopHeight:" + mTopHeight + " isDragRecyInTop：" + isDragRecyInTop.get())
//                    return true
                    if ((mTopHeight - dragBtnHeight) > 0) {
                        //还没到顶部
                        d("滚动到顶部333")
                        return true
                    }
                    d("滚动到顶部444")
                    return isDragRecyInTop.get()
                }
                return false
            }

            override fun clampViewPositionVertical(child: View, topOrg: Int, dy: Int): Int {
                var top = topOrg
                d(
                    TAG, "ViewDragHelper clampViewPositionVertical params: " + top
                            + " widget height: " + measuredHeight
                            + " dragBtnHeight: " + dragBtnHeight
                )
                mDragAfterTouch = true
                val isTopLayout = (child === topView)
                val isDragLayout = (child === dragBtn)
                val isBottomLayout = (child === bottomView)
                if (isDragLayout) {
                    d("ViewDragHelper clampViewPositionVertical 拖拽控件事件")
                    //拖拽控件事件
                    if (top >= height - MIN_BOTTOM - dp2px(stopHeight)) {
                        //底部边界--如果当前边界少于阈值，则不改变
                        top = height - MIN_BOTTOM - dp2px(stopHeight)
                    } else if (top <= MIN_TOP) {
                        //顶部边界
                        top = MIN_TOP
                    }
                    return top
                } else if (isBottomLayout) {
                    if (top >= height - MIN_BOTTOM - dp2px(stopHeight)) {
                        top = height - MIN_BOTTOM - dp2px(stopHeight)
                    } else if (top <= MIN_TOP) {
                        //顶部边界
                        top = MIN_TOP
                    }
                    d("ViewDragHelper clampViewPositionVertical bottom设置的top: $top")
                    return top
                }
                d("ViewDragHelper clampViewPositionVertical 事件还没拦截")
                return top
            }

            override fun getViewVerticalDragRange(child: View): Int {
//                val result = measuredHeight - child.measuredHeight - MIN_TOP
                val result = measuredHeight
                d(TAG, "ViewDragHelper getViewVerticalDragRange params--------------: $result")
                return result
            }

            override fun getViewHorizontalDragRange(child: View): Int {
                return 0
            }

            override fun onViewPositionChanged(
                changedView: View,
                left: Int,
                top: Int,
                dx: Int,
                dy: Int
            ) {
                d(
                    TAG,
                    "ViewDragHelper onViewPositionChanged params--------------: dy $dy top: $top mTopHeight$mTopHeight"
                )
                super.onViewPositionChanged(changedView, left, top, dx, dy)
                val isTopLayout = changedView === topView
                val isDragLayout = changedView === dragBtn
                val isBottomLayout = changedView === bottomView
                d(TAG, "ViewDragHelper onViewPositionChanged isTopLayout: $isTopLayout")
                d(TAG, "ViewDragHelper onViewPositionChanged isDragLayout: $isDragLayout")
                d(TAG, "ViewDragHelper onViewPositionChanged isBottomLayout: $isBottomLayout")
                if (isDragLayout) {
                    //拖动控件布局
                    val topViewLayoutParams = topView.layoutParams as LayoutParams
                    mTopHeight = Math.max(0, topViewLayoutParams.height + dy)
                    setOffset(mTopHeight)
                } else if (isBottomLayout) {
                    //还可以绘制
                    val topViewLayoutParams = topView.layoutParams as LayoutParams
                    mTopHeight = Math.max(0, topViewLayoutParams.height + dy)
                    setOffset(mTopHeight, 1)
                }
            }
        })
        //初始化布局高度
        postDelayed({ setOffset(getDefaultHeight(), 1) }, 20)
    }

    /**
     * 默认高度
     * */
    private fun getDefaultHeight(): Int {
        return measuredHeight - MIN_BOTTOM - dragBtnHeight
    }

    override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
        //计算是上拉还是下拉
        val action = ev.action
        when (action) {
            MotionEvent.ACTION_DOWN -> d("onInterceptTouchEvent: ACTION_DOWN")
            MotionEvent.ACTION_MOVE -> d("onInterceptTouchEvent: ACTION_MOVE")
            MotionEvent.ACTION_UP -> d("onInterceptTouchEvent: ACTION_UP")
            MotionEvent.ACTION_CANCEL -> d("onInterceptTouchEvent: ACTION_CANCEL")
        }
        return dragHelper.shouldInterceptTouchEvent(ev)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        val action = event.action
        when (action) {
            MotionEvent.ACTION_DOWN -> d("onTouchEvent: ACTION_DOWN")
            MotionEvent.ACTION_MOVE -> d("onTouchEvent: ACTION_MOVE")
            MotionEvent.ACTION_UP -> d("onTouchEvent: ACTION_UP")
            MotionEvent.ACTION_CANCEL -> d("onTouchEvent: ACTION_CANCEL")
        }
        dragHelper.processTouchEvent(event)
        return true
    }

    override fun onFinishInflate() {
        super.onFinishInflate()
        try {
            topView = findViewById(R.id.itemDragHelperViewTop)
            dragBtn = findViewById(R.id.itemDragHelperViewMiddle)
            bottomView = findViewById(R.id.itemDragHelperViewBottom)
            val llRoot: LinearLayout = findViewById(R.id.llRoot)
            dragBtn.post {
                dragBtnHeight = dragBtn.measuredHeight
                d("初始化拖拽高度： $dragBtnHeight")
            }

            val topParent = findViewById<RelativeLayout>(R.id.itemDragHelperViewTopParent)
            val middleParent = findViewById<RelativeLayout>(R.id.itemDragHelperViewMiddleParent)
            val bottomParent = findViewById<RelativeLayout>(R.id.itemDragHelperViewBottomParent)

            llRoot.post {
                mListener?.inflateView(topParent, middleParent, bottomParent)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }


    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
    }

    /**
     * 位置回弹恢复--上中下
     */
    private fun resetPositionAnim() {
        if (!mDragAfterTouch) {
            return
        }
        val currentHeight = mTopHeight.toFloat()
        val midHeight = measuredHeight / 2.0f
        val top = 0f
        val bottom = measuredHeight.toFloat()
        d("resetPositionAnim: $currentHeight")
        if (currentHeight in midHeight..bottom) {
            //底部
            val mid = (bottom - midHeight) / 2f
            if (currentHeight - midHeight < mid) {
                //底部靠上--移动到中部距离
                setOffsetWithAnim(currentHeight.toInt(), midHeight.toInt(), 1, 2)
            } else {
                //底部靠下--移到最底部
                setOffsetWithAnim(currentHeight.toInt(), getDefaultHeight(), 0, 3)
            }
        } else if (currentHeight in top..midHeight) {
            //上部
            val mid = (midHeight - top) / 2f
            if (currentHeight < mid) {
                //上部靠上--移到最顶部
                setOffsetWithAnim(currentHeight.toInt(), MIN_TOP, 1, 1)
            } else {
                //上部靠下--移动到中部距离
                setOffsetWithAnim(currentHeight.toInt(), midHeight.toInt(), 1, 2)
            }
        }
    }

    //外部调用----------------------------------------------------

    fun initDragRecyclerView(view: View?) {
        if (view is DragRecyclerView) {
            dragRecyclerView = view
            d("有一个DragRecyclerView")
            dragRecyclerView?.setScrollEventListener(object : ScrollEventListener {

                override fun completeShowTop(complete: Boolean) {
                    d("滚动到顶部：${complete}")
                    isDragRecyInTop.set(complete)
                }
            })
        }
    }

    fun setStopHeight(height: Int) {
        stopHeight = height
    }

    /**
     * @param type 0默认 1底部
     * */
    fun setOffset(topHeight: Int, type: Int = 0) {
        //改变顶部区域高度----------------------------------------------------
        val topViewLayoutParams = topView.layoutParams as LayoutParams
        topViewLayoutParams.height = topHeight
        topView.layoutParams = topViewLayoutParams
        //改变底部区域高度----------------------------------------------------
        val bottomViewLayoutParams = bottomView.layoutParams as LayoutParams
        val bottomHeight = height - topViewLayoutParams.height -
                (if (type == 1) dragBtnHeight else 0)
        bottomViewLayoutParams.height = bottomHeight
        bottomView.layoutParams = bottomViewLayoutParams
    }

    /**
     * @param org 1顶部 2中间 3底部
     * */
    fun setOffsetWithAnim(current: Int, target: Int, type: Int = 0, org: Int = 0) {
        mTopHeight = target
        val valueAnimator = ValueAnimator.ofInt(current, target)
        valueAnimator.interpolator = LinearInterpolator()
        valueAnimator.duration = mSetOffAnimTime
        valueAnimator.addUpdateListener(ValueAnimator.AnimatorUpdateListener { animation ->
            val animatedValue = animation.animatedValue as Int
            setOffset(animatedValue, type)
        })
        valueAnimator.doOnEnd {
            when (org) {
                1 -> {
                    mListener?.toTop()
                }
                2 -> {
                    mListener?.toMiddle()
                }
                3 -> {
                    mListener?.toBottom()
                }
            }
        }
        valueAnimator.start()
    }

    companion object {
        private val TAG = DragLayout::class.java.simpleName
    }


    //监听
    fun setDragLayoutEventListener(listener: DragLayoutEventListener) {
        this.mListener = listener
    }
}

